/* =============================================================
 * Your Grandmother's guide to Algorithms
 * =============================================================
 *
 * Copyright (c) 2007, Saverio Miroddi
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright 
 *       notice, this list of conditions and the following disclaimer in the 
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the SaverioMiroddiSoftware nor the names of its 
 *       contributors may be used to endorse or promote products derived from 
 *       this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 * ---------------------------
 * JGraphTreeComponent.java
 * ---------------------------
 *
 */
package treegui.graphlibwrappers;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JComponent;

import org.jgraph.JGraph;
import org.jgraph.graph.DefaultCellViewFactory;
import org.jgraph.graph.DefaultEdge;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.DefaultGraphModel;
import org.jgraph.graph.DefaultPort;
import org.jgraph.graph.GraphConstants;
import org.jgraph.graph.GraphLayoutCache;

import treegui.nodewrappers.IGuiNode;

/**
 * TreeFactory subclass using JGraph.<br>
 * Display representation is a bit misaligned because it doesn't take into
 * account some internal gui borders.<br>
 * 
 * @author Saverio Miroddi
 */
public class JGraphTreeComponent extends AbsTreeComponent {
	private DefaultGraphCell[] boxes;
	private List<DefaultGraphCell> cells;
	
	public JGraphTreeComponent(List<IGuiNode> treeData, Dimension screenOfs) {
		super(treeData, screenOfs);
	}
	
	@Override
	protected void init() {
		/* we use the max positions number. this array is used for keep box 
		 * references needed by edges */
		boxes = new DefaultGraphCell[treeData.size()];
		
		/* this is used as the resulting set of boxes+edges */
		cells = new ArrayList<DefaultGraphCell>();
	}

	@Override
	protected void setBox(int posIdx) {
		IGuiNode node = treeData.get(posIdx); 
		
		String boxText = node.toString();
		DefaultGraphCell cell = new DefaultGraphCell(boxText);
		
		Point2D pos = node.getPosition();
		double x0 = pos.getX();	
		double y0 = pos.getY();
		
		if (screenOfs != null) {
			x0 += screenOfs.width;
			y0 += screenOfs.height;
		}

		Color nodeColor = node.getColor();

		GraphConstants.setBounds(cell.getAttributes(),
				new Rectangle2D.Double(x0, y0, -1, -1));
		
//		GraphConstants.setBackground(cell.getAttributes(), node.getColor());
//		GraphConstants.setGradientColor(cell.getAttributes(), node.getColor());
		GraphConstants.setBorder(cell.getAttributes(), 
								 BorderFactory.createLineBorder(nodeColor, 2));
//		GraphConstants.setBorderColor(cell.getAttributes(), nodeColor);
		GraphConstants.setAutoSize(cell.getAttributes(), true);
		GraphConstants.setInset(cell.getAttributes(), 4);

		GraphConstants.setOpaque(cell.getAttributes(), true);
		DefaultPort port = new DefaultPort();
		cell.add(port);
		
		boxes[posIdx] = cell;
		cells.add(cell);
	}
	
	@Override
	protected void setArrow(int fromPos, int toPos) {
		DefaultEdge arrow = new DefaultEdge();
		arrow.setSource(boxes[fromPos].getChildAt(0));
		arrow.setTarget(boxes[toPos].getChildAt(0));
		
		GraphConstants.setLineEnd(
				arrow.getAttributes(), GraphConstants.ARROW_CLASSIC);
		GraphConstants.setEndFill(arrow.getAttributes(), true);

		cells.add(arrow);
	}

	@Override
	protected JComponent getResultingGraphComponent() {
		GraphLayoutCache layoutCache = new GraphLayoutCache(
				new DefaultGraphModel(), new DefaultCellViewFactory());
		JGraph jgraph = new JGraph(layoutCache);
		
		DefaultGraphCell[] cellsArr = new DefaultGraphCell[cells.size()];
		cells.toArray(cellsArr);
		
		// Very cheap programming: it's possible to pass every class
		// inside insert(), but if it's not a DefaultGraphCell[], the
		// method throws an obscure and misleading NullPointerException.
		
		jgraph.getGraphLayoutCache().insert(cellsArr);
		
		return jgraph;
	}
}